﻿using Scenario_Editor.TerrainTools.TerrainGenerator;
using SimplexNoise;
using System;
using System.Windows.Forms;

namespace Scenario_Editor.TerrainGenerator
{
    public partial class SimplexNoise : UserControl, ITerrainGenerator
    {
        #region Private Fields

        private Random random;

        #endregion Private Fields

        #region Public Constructors

        public SimplexNoise()
        {
            InitializeComponent();
            this.random = new Random();
        }

        #endregion Public Constructors

        #region Public Events

        public event EventHandler ValueChanged;

        #endregion Public Events

        #region Public Properties

        public string GeneratorName
        {
            get { return "Simplex Noise"; }
        }

        public int NumberOfBlocksX { get; set; }

        public int NumberOfBlocksY { get; set; }

        public float TerrainSizeX { get; set; }

        public float TerrainSizeY { get; set; }

        #endregion Public Properties

        #region Public Methods

        public float[,] GetValues()
        {
            int numberOfRuns = (int)this.numericUpDown2.Value;
            float scale = (float)this.numericUpDown1.Value;
            float offset = (float)this.nud_Seed.Value;
            float factorX = TerrainSizeX / (float)NumberOfBlocksX;
            float factorY = TerrainSizeY / (float)NumberOfBlocksY;
            //TerrainSizeX *= scale;
            //TerrainSizeY *= scale;
            //offset = 0;

            factorX *= scale;
            factorY *= scale;

            float[,] sectores = new float[NumberOfBlocksX, NumberOfBlocksY];

            float min = float.MaxValue, max = float.MinValue;
            float stepFactor = 2;
            for (int i = 0; i < numberOfRuns; i++)
            {
                for (int x = 0; x < NumberOfBlocksX; x++)
                {
                    for (int y = 0; y < NumberOfBlocksY; y++)
                    {
                        float XX = ((float)(x * factorX + offset + i * TerrainSizeX) * (1.0f / (i + 1 * (float)Math.Pow(stepFactor,2) )));
                        float YY = ((float)(y * factorY + offset + i * TerrainSizeY) * (1.0f / (i + 1 * (float)Math.Pow(stepFactor,2) )));
                        //float YY = ((float)y * factorY + offset);
                        float value = Noise.Generate(XX, YY);
                        //value += 1.0f;
                        //value *= 5.5f;
                        if (this.checkBox_Quardratic.Checked)
                            value = (float)Math.Pow(value, 3);
                        sectores[x, y] += value;
                    }
                }
                factorX *= stepFactor;
                factorY *= stepFactor;
            }

            // Normalisize between -1.0f and 1.0f
            float minValue = float.MaxValue;
            float maxValue = float.MinValue;
            for (int x = 0; x < this.NumberOfBlocksX; x++)
            {
                for (int y = 0; y < this.NumberOfBlocksY; y++)
                {
                    minValue = Math.Min(minValue, sectores[x, y]);
                    maxValue = Math.Max(maxValue, sectores[x, y]);
                }
            }

            float rangeMinMax = maxValue - minValue;

            float maxAbsolute = Math.Max(Math.Abs(maxValue), Math.Abs(minValue));

            for (int x = 0; x < this.NumberOfBlocksX; x++)
            {
                for (int y = 0; y < this.NumberOfBlocksY; y++)
                {
                    sectores[x, y] /= maxAbsolute;
                }
            }

            return sectores;
        }

        #endregion Public Methods

        #region Private Methods

        private void button_NewRandom_Click(object sender, EventArgs e)
        {
            decimal factor = 10000;
            this.nud_Seed.Value = (decimal)this.random.Next((int)(this.nud_Seed.Minimum * factor), (int)(Math.Min((int)(this.nud_Seed.Maximum * factor), int.MaxValue))) / factor;
        }

        private void OnValueChanged(object sender, EventArgs e)
        {
            if (this.ValueChanged != null)
                this.ValueChanged(this, EventArgs.Empty);
        }

        #endregion Private Methods
    }
}